import React from 'react';
import { Controller, useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';
import {
  Box,
  BulletList,
  FormStatusMessage,
  Grid,
  GridItem,
  Input,
  MainButton,
  makeToast,
  NotificationBanner,
  NumberInput,
  SingleSelect,
  Text,
} from '@nova-hf/ui';
import StepWrapper from 'beta/containers/layout/StepWrapper';
import Authentication from 'beta/store/authentication';
import { IContext } from 'beta/typings/context';
import { formatPrice } from 'beta/utils/helpers';
import { inject, observer } from 'mobx-react';
import { useRouter } from 'next/router';
import {
  AdjustmentCategory,
  AdjustmentRequestInput,
  useAdjustmentRequestMutation,
  useContractQuery,
  useCurrentPeriodQuery,
} from 'typings/graphql';
import { useTranslation } from 'utils/i18n';

type LeidrettingProps = {
  customerId: string;
  contractId: string;
  authentication?: Authentication;
};

const Leidretting = ({ customerId, contractId, authentication }: LeidrettingProps) => {
  const { t } = useTranslation('service');
  const isStaff = authentication?.isStaff;
  const router = useRouter();
  const reasons = [
    t('adjustments.reasons.moved'),
    t('adjustments.reasons.other'),
    t('adjustments.reasons.termination'),
    t('adjustments.reasons.wrongService'),
    t('adjustments.reasons.wrongCharge'),
    t('adjustments.reasons.noUsage'),
  ];
  const categories = [
    { value: AdjustmentCategory.Fiber, title: t('adjustments.fiber') },
    { value: AdjustmentCategory.Unknown, title: t('adjustments.other') },
  ];
  const { data, loading, error } = useContractQuery({
    variables: {
      input: {
        id: contractId.toString(),
      },
    },
  });
  const contract = data?.contract;

  const {
    data: periodData,
    loading: periodLoading,
    error: periodError,
    refetch,
  } = useCurrentPeriodQuery({
    variables: {
      input: {
        id: contract?.id ?? '',
      },
    },
    skip: !contract?.id,
  });

  const [adjustmentRequest, { loading: adjustmentRequestLoading }] = useAdjustmentRequestMutation({
    onCompleted(data) {
      if (data?.adjustmentRequest?.message) {
        refetch();
        makeToast.success(t('adjustments.success'), '');
        router.push(`/beta/${customerId}/askriftir/${contractId}`);
      }
    },
    onError(error) {
      if (error) {
        makeToast.danger(t('adjustments.fail'), error.message);
      }
    },
  });

  const color = 'purple';
  const currentPeriod = periodData?.currentPeriod;

  const {
    control,
    handleSubmit,
    setValue,
    formState: { isValid },
    trigger,
  } = useForm<AdjustmentRequestInput>({
    defaultValues: {
      amount: undefined,
      description: '',
      reason: '',
      category: AdjustmentCategory.Unknown,
      salesPersonNumber: undefined,
    },
    delayError: 500,
    mode: 'onChange',
  });

  const onSubmit = (formData: AdjustmentRequestInput) => {
    adjustmentRequest({
      variables: {
        input: {
          contractId: contract?.id ?? '',
          periodId: currentPeriod?.id ?? '',
          amount: formData.amount,
          description: formData.description,
          reason: formData.reason,
          category: formData.category,
          salesPersonNumber: formData.salesPersonNumber,
        },
      },
    });
  };

  const loadingCheck = loading || periodLoading || adjustmentRequestLoading;

  return (
    <StepWrapper
      color={color}
      returnUrl={`/beta/${customerId}/askriftir/${contractId}`}
      title={data?.contract?.payer?.name ?? t('adjustments.adjustment')}
      subTitle={data?.contract?.variant?.productName ?? ''}
      icon="novaLogo"
      childrenBottom={
        <Text color="white" variant="h6">
          {formatPrice(currentPeriod?.totalCharge ?? 0)}
        </Text>
      }
    >
      {contract && isStaff ? (
        <Box renderAs="form" onSubmit={handleSubmit(onSubmit)}>
          <Grid gridTemplate={{ sm: 4 }}>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Box marginBottom={3} display="flex" flexDirection="column">
                <Text color={color} variant="eyebrowLarge" marginTop={3}>
                  {t('adjustments.eyebrow')}
                </Text>
                <Text color="black100" variant="h6" marginTop={2}>
                  {t('adjustments.title')}
                </Text>
                <Text marginTop={3} color="black100" variant="pMediumRegular">
                  {t('adjustments.sectionOne')}
                </Text>
                <Text marginTop={3} color="black100" variant="pMediumRegular">
                  {t('adjustments.sectionTwo')}
                </Text>
                <Text marginTop={5} color="black100" variant="pMediumBold">
                  {t('adjustments.bulletTitle')}
                </Text>
                <Box style={{ hyphens: 'auto' }} padding={2}>
                  <BulletList
                    bulletColor="black100"
                    isBold={false}
                    bullets={[
                      {
                        id: '1',
                        text: t('adjustments.bulletOne'),
                        textVariant: 'pMediumRegular',
                      },
                      {
                        id: '2',
                        text: t('adjustments.bulletTwo'),
                        textVariant: 'pMediumRegular',
                      },
                      {
                        id: '3',
                        text: t('adjustments.bulletThree'),
                        textVariant: 'pMediumRegular',
                      },
                      {
                        id: '4',
                        text: t('adjustments.bulletFour'),
                        textVariant: 'pMediumRegular',
                      },
                      {
                        id: '5',
                        text: t('adjustments.bulletFive'),
                        textVariant: 'pMediumRegular',
                      },
                    ]}
                    gap={1}
                    size="medium"
                    verticalSpace={1}
                  />
                </Box>
              </Box>
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Controller
                name="category"
                control={control}
                rules={{
                  required: true,
                }}
                render={({ field, formState: { errors } }) => {
                  const { name } = field;

                  return (
                    <Box>
                      <SingleSelect
                        color={color}
                        defaultMenuIsOpen={false}
                        placeholder={t('adjustments.chooseCategory')}
                        id="category"
                        label={t('adjustments.chooseCategory')}
                        maxMenuHeight={250}
                        onChange={(e) =>
                          setValue('category', (e?.value as AdjustmentCategory) ?? '')
                        }
                        isClearable={false}
                        options={categories.map((category) => ({
                          label: category.title,
                          value: category.value,
                        }))}
                        required
                        isDisabled={loadingCheck}
                      />
                      <ErrorMessage
                        errors={errors}
                        name={name}
                        render={() => (
                          <FormStatusMessage
                            message={t('discounts.categoryError')}
                            status="error"
                          />
                        )}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Controller
                name="amount"
                rules={{
                  required: t('adjustments.amountMissing').toString(),
                  validate: {
                    min: (value) =>
                      Number(value) > 0 ? true : t('adjustments.amountError').toString(),
                    max: (value) =>
                      Number(value) <= (currentPeriod?.totalCharge || 0)
                        ? true
                        : t('adjustments.amountError').toString(),
                  },
                }}
                control={control}
                render={({ field, formState: { errors } }) => {
                  const { name } = field;
                  return (
                    <Box>
                      <NumberInput
                        id="amount"
                        numberType="number"
                        label={t('adjustments.amount')}
                        required
                        name={name}
                        value={field?.value?.toString() ?? ''}
                        onChange={(value) => {
                          if (!value) {
                            setValue('amount', undefined);
                          } else {
                            setValue('amount', Number(value));
                          }
                          trigger('amount');
                        }}
                        onBlur={field.onBlur}
                      />
                      <ErrorMessage
                        errors={errors}
                        name={name}
                        render={({ message }) => (
                          <FormStatusMessage message={message} status="error" />
                        )}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Controller
                name="reason"
                control={control}
                rules={{
                  required: t('adjustments.reasonError').toString(),
                }}
                render={({ field, formState: { errors } }) => {
                  const { name, onChange } = field;
                  return (
                    <Box>
                      <SingleSelect
                        color={color}
                        defaultMenuIsOpen={false}
                        placeholder={t('adjustments.chooseReason')}
                        id="reason"
                        label={t('adjustments.chooseReason')}
                        maxMenuHeight={250}
                        onChange={(e) => {
                          onChange(e?.value);
                        }}
                        isClearable={false}
                        options={reasons.map((reason) => ({
                          label: reason,
                          value: reason,
                        }))}
                        required
                        isDisabled={loadingCheck}
                      />
                      <ErrorMessage
                        errors={errors}
                        name={name}
                        render={({ message }) => (
                          <FormStatusMessage message={message} status="error" />
                        )}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Controller
                name="description"
                control={control}
                rules={{
                  required: t('adjustments.descriptionError').toString(),
                  maxLength: {
                    value: 250,
                    message: t('adjustments.toLong'),
                  },
                }}
                render={({ field, formState: { errors } }) => {
                  const { name, value, onChange } = field;
                  return (
                    <Box>
                      <Input
                        id="description"
                        label={t('adjustments.description')}
                        isBold={true}
                        required
                        value={value ?? ''}
                        onChange={onChange}
                        name={name}
                      />
                      <ErrorMessage
                        errors={errors}
                        name={name}
                        render={({ message }) => (
                          <FormStatusMessage message={message} status="error" />
                        )}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Controller
                name="salesPersonNumber"
                rules={{
                  required: t('adjustments.salesNumberMissing').toString(),
                  validate: {
                    min: (value) =>
                      Number(value) > 0 ? true : t('adjustments.salesNumberError').toString(),
                    max: (value) =>
                      Number(value) <= 9999 ? true : t('adjustments.salesNumberError').toString(),
                  },
                }}
                control={control}
                render={({ field: { name, value, onBlur }, formState: { errors } }) => {
                  return (
                    <Box>
                      <NumberInput
                        id="salesPersonNumber"
                        numberType="number"
                        label={t('adjustments.salesNumber')}
                        required
                        name={name}
                        value={value?.toString() ?? ''}
                        onChange={(value) => {
                          if (!value) {
                            setValue('salesPersonNumber', undefined);
                          } else {
                            setValue('salesPersonNumber', Number(value));
                          }
                          trigger('salesPersonNumber');
                        }}
                        onBlur={onBlur}
                      />
                      <ErrorMessage
                        errors={errors}
                        name={name}
                        render={({ message }) => (
                          <FormStatusMessage message={message} status="error" />
                        )}
                      />
                    </Box>
                  );
                }}
              />
            </GridItem>
            {(error || periodError || !data) && (
              <GridItem gridColumn={{ sm: 'span4' }}>
                <FormStatusMessage message={t('adjustments.error')} status="error" />
              </GridItem>
            )}
            <GridItem gridColumn={{ sm: 'span4' }}>
              <Box
                display="flex"
                marginTop={6}
                marginBottom={10}
                justifyContent="flex-end"
                flexDirection={{ sm: 'column', md: 'row' }}
              >
                <Box display="flex" width={{ sm: '100%', md: '4/12' }}>
                  <MainButton
                    text={t('adjustments.buttonText')}
                    colorScheme={color}
                    isSubmitButton
                    isLoading={loadingCheck}
                    isDisabled={!isValid}
                  />
                </Box>
              </Box>
            </GridItem>
          </Grid>
        </Box>
      ) : (
        <Box>
          <NotificationBanner
            description={t('adjustments.noAdjustment')}
            eyebrowText={t('adjustments.adjustment')}
            icon="creditcardOff"
            color={color}
            mainButtonColored={{
              text: t('adjustments.back'),
              color: color,
              onClick: () => {
                router.push(`/beta/${customerId}/askriftir/${contractId}`);
              },
            }}
            title={t('adjustments.noAdjustmentTitle')}
          />
        </Box>
      )}
    </StepWrapper>
  );
};

Leidretting.getInitialProps = ({ pathname, query }: IContext) => {
  return {
    pathname,
    customerId: query.customerId,
    contractId: query.contractId,
    namespacesRequired: ['service'],
  };
};

export default inject('authentication', 'steps', 'ui')(observer(Leidretting));
